//
// Created on 2024/2/27.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "InputHandler.h"
#include "napi/adapter/TouchEventHandler.h"
#include "napi/helper/Js_GameEngineHelper.h"
#include "napi/native_manager.h"

int TouchTracker::nextTouchId = 0;

std::list<TouchTracker *> InputHandler::touchTrackers;
std::list<TapTracker *> InputHandler::tapTrackers;

TouchTracker* InputHandler::getTouchById(int32_t pointerId){
    for(auto touchTracker : touchTrackers){
        if(touchTracker->pointerId == pointerId){
            return touchTracker;
        }
    }
    return nullptr;
}

TapTracker *InputHandler::getTapById(int32_t touchId) {
    for (auto tapTracker : tapTrackers) {
        if (tapTracker->touchId == touchId) {
            return tapTracker;
        }
    }
    return nullptr;
}

void InputHandler::handleTouchBegin(OH_NativeXComponent_TouchEvent* touchEvent){
    TouchTracker* touchTracker = new TouchTracker(touchEvent->id);

    //init the start point at the beginning
    touchTracker->startPoint = new TouchPoint(touchEvent->x, touchEvent->y, touchEvent->timeStamp);
    touchTracker->lastPoint = new TouchPoint(touchEvent->x, touchEvent->y, touchEvent->timeStamp);
    
    touchTracker->type = touchEvent->type;
    
    //insert the element into the list to trace the history track of every finger touch
    touchTrackers.push_back(touchTracker);
    
    TouchEventHandler::getInstance()->dispatchTouchEvent(touchTracker);
}

void InputHandler::handleTouchEnd(OH_NativeXComponent_TouchEvent *touchEvent){
    TouchTracker* touchTracker = getTouchById(touchEvent->id);
    
    //return if the track is not initialized
    if (touchTracker == nullptr || touchTracker->startPoint == nullptr) {
        return;
    }

    TouchPoint* touchPoint = new TouchPoint(touchEvent->x, touchEvent->y, touchEvent->timeStamp);
    touchTracker->update(touchPoint, touchEvent->type);
    TouchEventHandler::getInstance()->dispatchTouchEvent(touchTracker);
    delete touchTracker;
    touchTrackers.remove(touchTracker);
}

void InputHandler::handleTouchMove(OH_NativeXComponent_TouchEvent *touchEvent) {
    for (uint32_t i = 0; i < touchEvent->numPoints; i++) {
        TouchTracker *touchTracker = InputHandler::getTouchById(touchEvent->touchPoints[i].id);
        // pass if the track is not initialized
        if (touchTracker == nullptr || touchTracker->startPoint == nullptr) {
            continue;
        }

        float deltaX = abs(touchEvent->touchPoints[i].x - touchTracker->lastPoint->_x);
        float deltaY = abs(touchEvent->touchPoints[i].y - touchTracker->lastPoint->_y);
        // pass if the movement is small
        if ((deltaX < 1.0f) && (deltaY < 1.0f)) {
            continue;
        }

        TouchPoint *touchPoint = new TouchPoint(touchEvent->touchPoints[i].x, touchEvent->touchPoints[i].y,
                                                touchEvent->touchPoints[i].timeStamp);
        touchTracker->update(touchPoint, touchEvent->type);
        TouchEventHandler::getInstance()->dispatchTouchEvent(touchTracker);
    }
}

void InputHandler::handleTouchCancel(OH_NativeXComponent_TouchEvent *touchEvent) {
    for (uint32_t i = 0; i < touchEvent->numPoints; i++) {
        TouchTracker *touchTracker = InputHandler::getTouchById(touchEvent->touchPoints[i].id);
        // pass if the track is not initialized
        if (touchTracker == nullptr || touchTracker->startPoint == nullptr) {
            continue;
        }

        TouchPoint *touchPoint = new TouchPoint(touchEvent->touchPoints[i].x, touchEvent->touchPoints[i].y,
                                                touchEvent->touchPoints[i].timeStamp);
        touchTracker->update(touchPoint, touchEvent->type);
        TouchEventHandler::getInstance()->dispatchTouchEvent(touchTracker);
        delete touchTracker;
        touchTrackers.remove(touchTracker);
    }
}


void InputHandler::handleTapEvent(OH_NativeXComponent_TouchEvent *touchEvent) {
    TapTracker* tapTracker = getTapById(touchEvent->id);
    if(tapTracker == nullptr) {
        tapTracker = new TapTracker;
        tapTracker->touchId = touchEvent->id;
        tapTrackers.push_back(tapTracker);
    }
    
    tapTracker->update(touchEvent);
    
    if(tapTracker->tapPoint){
        TouchEventHandler::getInstance()->dispatchTabEvent(tapTracker);
    }
}